package com.ece.persistence;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.RollbackException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class PersistenceUtil {
	private static Log log = LogFactory.getLog(PersistenceUtil.class);
	private static EntityManagerFactory emf;
	private static final ThreadLocal<EntityManager> em = new ThreadLocal<EntityManager>();
	private static final ThreadLocal<EntityTransaction> tx = new ThreadLocal<EntityTransaction>();

	public static void init() {
		if (PersistenceUtil.emf == null)
			PersistenceUtil.emf = Persistence
			.createEntityManagerFactory("LivraisonPU");
	}

	public static void destroy() {
		if (PersistenceUtil.emf != null)
			PersistenceUtil.emf.close();
	}

	/**
	 * Returns an EntityManager for the current thread, creating one if there is
	 * none.
	 * 
	 * @return
	 */
	public static EntityManager getEM() {
		EntityManager anEM = em.get();
		if (anEM == null || !anEM.isOpen()) {
			log.debug("Opening session");
			anEM = PersistenceUtil.emf.createEntityManager();
			PersistenceUtil.em.set(anEM);
		}
		return anEM;
	}

	/**
	 * Close the EM associated to the current thread (if open).
	 */
	public static void closeEM() {
		EntityManager anEM = em.get();
		PersistenceUtil.em.set(null);
		if (anEM != null) {
			log.debug("Closing session");
			anEM.close();
		}
	}

	/**
	 * Begin a new transaction for the current thread / EM
	 * 
	 * @return
	 */
	public static void beginTransaction() {
		EntityTransaction aTx = tx.get();
		// Begin a new transaction, if this Thread has none yet
		if (aTx == null || !aTx.isActive()) {
			log.debug("Beginning a transaction");
			aTx = PersistenceUtil.getEM().getTransaction();
			aTx.begin();
			PersistenceUtil.tx.set(aTx);
		}
	}

	/**
	 * Commit the current thread transaction (if active)
	 */
	public static void commitTransaction() {
		EntityTransaction aTx = tx.get();
		try {
			if (aTx != null && aTx.isActive()) {
				log.debug("Committing transaction");
				aTx.commit();
			}
			PersistenceUtil.tx.set(null);
		} catch (RollbackException e) {
			PersistenceUtil.rollbackTransaction();
			PersistenceUtil.closeEM();
		}
	}

	/**
	 * Rollback the current thread transaction (if active and marked for
	 * rollback)
	 */
	public static void rollbackTransaction() {
		EntityTransaction aTx = tx.get();
		if (aTx != null && aTx.isActive() && aTx.getRollbackOnly()) {
			log.debug("Rollback transaction");
			aTx.rollback();
		}
		PersistenceUtil.tx.set(null);
		PersistenceUtil.closeEM();
	}
}
